<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>日志管理系统</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #3498db;
            --primary-dark: #2980b9;
            --secondary-color: #e74c3c;
            --gray-light: #f5f6fa;
            --text-color: #34495e;
        }
        
        body {
            font-family: "微软雅黑", "Microsoft YaHei", sans-serif;
            color: var(--text-color);
            background-color: #f5f7fa;
        }
        
        .sidebar {
            width: 250px;
            position: fixed;
            top: 0;
            left: 0;
            height: 100vh;
            background-color: #2c3e50;
            color: white;
            padding-top: 20px;
            box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
            z-index: 100;
        }
        
        .main-content {
            margin-left: 250px;
            padding: 20px;
        }
        
        .header {
            background-color: white;
            border-radius: 10px;
            padding: 15px 20px;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
        }
        
        .stats-card {
            background-color: white;
            border-radius: 10px;
            padding: 15px;
            margin-bottom: 20px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
            height: 100%;
            transition: all 0.3s;
        }
        
        .stats-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }
        
        .log-container {
            background-color: white;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
            margin-bottom: 20px;
        }
        
        .log-content {
            background-color: #1e272e;
            color: #ecf0f1;
            padding: 15px;
            border-radius: 5px;
            font-family: monospace;
            height: 400px;
            overflow-y: auto;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        
        .log-line {
            padding: 2px 0;
            border-bottom: 1px solid #34495e20;
        }
        
        .log-line:nth-child(even) {
            background-color: rgba(255, 255, 255, 0.05);
        }
        
        .log-level-ERROR {
            color: #e74c3c;
            font-weight: bold;
        }
        
        .log-level-WARN {
            color: #f39c12;
        }
        
        .log-level-INFO {
            color: #3498db;
        }
        
        .log-level-DEBUG {
            color: #2ecc71;
        }
        
        .log-files-list {
            max-height: 400px;
            overflow-y: auto;
        }
        
        .log-files-list .list-group-item {
            cursor: pointer;
            transition: all 0.2s;
        }
        
        .log-files-list .list-group-item:hover {
            background-color: var(--gray-light);
        }
        
        .log-files-list .list-group-item.active {
            background-color: var(--primary-color);
            border-color: var(--primary-color);
        }
        
        .file-error {
            color: var(--secondary-color);
        }
        
        .loading-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(255, 255, 255, 0.7);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 9999;
        }
        
        .loading-spinner {
            width: 50px;
            height: 50px;
            border: 5px solid #f3f3f3;
            border-top: 5px solid var(--primary-color);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        /* 自动刷新开关样式 */
        .form-switch .form-check-input {
            width: 3em;
            height: 1.5em;
        }
        
        .sidebar-nav {
            list-style: none;
            padding: 0;
        }
        
        .sidebar-nav li {
            padding: 10px 20px;
            margin-bottom: 5px;
        }
        
        .sidebar-nav li:hover {
            background-color: #34495e;
        }
        
        .sidebar-nav a {
            color: white;
            text-decoration: none;
            display: block;
        }
        
        .sidebar-nav .active {
            background-color: var(--primary-color);
            border-radius: 5px;
        }
        
        .login-modal {
            background-color: rgba(0, 0, 0, 0.4);
        }
        
        /* 日志标记格式 */
        .timestamp {
            color: #95a5a6;
        }
        
        .log-category {
            font-weight: bold;
            color: #9b59b6;
        }
    </style>
</head>
<body>
    <!-- 加载中遮罩 -->
    <div class="loading-overlay" id="loadingOverlay">
        <div class="loading-spinner"></div>
    </div>

    <!-- 侧边栏 -->
    <div class="sidebar">
        <div class="text-center mb-4">
            <h4>日志管理系统</h4>
            <p class="text-muted">v1.0.0</p>
        </div>
        <ul class="sidebar-nav">
            <li><a href="/"><i class="fas fa-chart-line me-2"></i> 首页</a></li>
            <li class="active"><a href="/admin/logs.html"><i class="fas fa-file-alt me-2"></i> 日志查看</a></li>
            <li><a href="/admin/cache.html"><i class="fas fa-database me-2"></i> 缓存管理</a></li>
            <li><a href="/admin/monitor.html"><i class="fas fa-eye me-2"></i> 系统监控</a></li>
        </ul>
    </div>

    <!-- 主内容区 -->
    <div class="main-content">
        <!-- 头部 -->
        <div class="header d-flex justify-content-between align-items-center">
            <h4><i class="fas fa-file-alt me-2"></i> 系统日志管理</h4>
            <button id="refreshBtn" class="btn btn-primary">
                <i class="fas fa-sync-alt me-2"></i> 刷新
            </button>
        </div>

        <!-- 统计卡片 -->
        <div class="row mb-4">
            <div class="col-md-3">
                <div class="stats-card text-center">
                    <i class="fas fa-folder text-primary mb-2" style="font-size: 2rem;"></i>
                    <h3 id="totalFilesCount">-</h3>
                    <p class="text-muted">日志文件总数</p>
                </div>
            </div>
            <div class="col-md-3">
                <div class="stats-card text-center">
                    <i class="fas fa-exclamation-triangle text-warning mb-2" style="font-size: 2rem;"></i>
                    <h3 id="errorFilesCount">-</h3>
                    <p class="text-muted">错误日志文件</p>
                </div>
            </div>
            <div class="col-md-3">
                <div class="stats-card text-center">
                    <i class="fas fa-hdd text-success mb-2" style="font-size: 2rem;"></i>
                    <h3 id="totalSize">-</h3>
                    <p class="text-muted">日志总大小</p>
                </div>
            </div>
            <div class="col-md-3">
                <div class="stats-card text-center">
                    <i class="fas fa-chart-pie text-danger mb-2" style="font-size: 2rem;"></i>
                    <h3 id="errorRate">-</h3>
                    <p class="text-muted">错误率</p>
                </div>
            </div>
        </div>

        <!-- 内容区 -->
        <div class="row">
            <!-- 左侧菜单 -->
            <div class="col-md-3">
                <div class="log-container">
                    <div class="d-flex justify-content-between align-items-center mb-3">
                        <h5><i class="fas fa-list me-2"></i> 日志文件</h5>
                        <div class="btn-group">
                            <button class="btn btn-sm btn-outline-primary category-btn active" data-category="app">应用</button>
                            <button class="btn btn-sm btn-outline-primary category-btn" data-category="monitor">监控</button>
                            <button class="btn btn-sm btn-outline-primary category-btn" data-category="system">系统</button>
                        </div>
                    </div>
                    <div class="input-group mb-3">
                        <span class="input-group-text"><i class="fas fa-search"></i></span>
                        <input type="text" class="form-control" id="fileSearchInput" placeholder="搜索文件...">
                    </div>
                    <div class="log-files-list">
                        <div class="list-group" id="logFilesList">
                            <!-- 日志文件列表将通过JavaScript加载 -->
                            <div class="text-center p-3 text-muted">
                                <i class="fas fa-spinner fa-spin me-2"></i> 加载中...
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- 右侧内容 -->
            <div class="col-md-9">
                <div class="log-container">
                    <div class="d-flex justify-content-between align-items-center mb-3">
                        <h5 id="currentLogTitle"><i class="fas fa-file-alt me-2"></i> 选择文件查看内容</h5>
                        <div>
                            <div class="form-check form-switch d-inline-block me-3">
                                <input class="form-check-input" type="checkbox" id="autoRefreshSwitch">
                                <label class="form-check-label" for="autoRefreshSwitch">自动刷新</label>
                            </div>
                            <div class="btn-group">
                                <button class="btn btn-sm btn-outline-secondary" id="downloadBtn" disabled>
                                    <i class="fas fa-download me-1"></i> 下载
                                </button>
                                <button class="btn btn-sm btn-outline-primary" id="clearBtn">
                                    <i class="fas fa-eraser me-1"></i> 清空
                                </button>
                            </div>
                        </div>
                    </div>
                    <div class="input-group mb-3">
                        <span class="input-group-text"><i class="fas fa-filter"></i></span>
                        <input type="text" class="form-control" id="logSearchInput" placeholder="筛选日志内容...">
                        <button class="btn btn-outline-secondary" type="button" id="filterErrorBtn">
                            <i class="fas fa-exclamation-circle me-1"></i> 只看错误
                        </button>
                    </div>
                    <div class="log-content" id="logContent">
                        <div class="text-center p-3 text-muted">
                            请选择左侧的日志文件查看内容
                        </div>
                    </div>
                    <div class="d-flex justify-content-between align-items-center mt-3">
                        <div>
                            <span class="badge bg-primary me-2">INFO</span>
                            <span class="badge bg-success me-2">DEBUG</span>
                            <span class="badge bg-warning text-dark me-2">WARN</span>
                            <span class="badge bg-danger">ERROR</span>
                        </div>
                        <div class="text-muted" id="logStats">
                            总行数: <span id="totalLines">0</span> | 显示行数: <span id="displayedLines">0</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 登录模态框 -->
    <div class="modal fade" id="loginModal" data-bs-backdrop="static" tabindex="-1" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">管理员登录</h5>
                </div>
                <div class="modal-body">
                    <div class="alert alert-danger d-none" id="loginError"></div>
                    <form id="loginForm">
                        <div class="mb-3">
                            <label for="username" class="form-label">用户名</label>
                            <input type="text" class="form-control" id="username" required>
                        </div>
                        <div class="mb-3">
                            <label for="password" class="form-label">密码</label>
                            <input type="password" class="form-control" id="password" required>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary" id="loginBtn">登录</button>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
    <script>
        // 全局变量
        let credentials = null;
        let currentCategory = 'app';
        let currentFile = null;
        let autoRefreshInterval = null;
        let logFiles = [];
        
        // DOM元素加载完成后执行
        $(document).ready(function() {
            // 检查是否已经登录
            const savedCredentials = localStorage.getItem('admin_credentials');
            if (savedCredentials) {
                credentials = savedCredentials;
                hideLoading();
                init();
            } else {
                showLoginModal();
            }
            
            // 设置事件监听
            $('#loginBtn').click(handleLogin);
            $('#refreshBtn').click(refreshData);
            $('.category-btn').click(handleCategoryChange);
            $('#fileSearchInput').on('input', filterLogFiles);
            $('#logSearchInput').on('input', filterLogContent);
            $('#filterErrorBtn').click(toggleErrorFilter);
            $('#autoRefreshSwitch').change(toggleAutoRefresh);
            $('#clearBtn').click(clearLogContent);
            $('#downloadBtn').click(downloadCurrentLog);
        });
        
        // 初始化页面
        function init() {
            loadLogStats();
            loadLogFiles(currentCategory);
        }
        
        // 显示登录模态框
        function showLoginModal() {
            hideLoading();
            const loginModal = new bootstrap.Modal(document.getElementById('loginModal'));
            loginModal.show();
        }
        
        // 处理登录
        function handleLogin() {
            const username = $('#username').val();
            const password = $('#password').val();
            
            if (!username || !password) {
                showLoginError('请输入用户名和密码');
                return;
            }
            
            showLoading();
            
            // 创建Basic Auth凭证
            credentials = btoa(`${username}:${password}`);
            
            // 测试API调用是否成功
            $.ajax({
                url: '/api/admin/logs/stats',
                type: 'GET',
                headers: {
                    'Authorization': `Basic ${credentials}`
                },
                success: function(response) {
                    hideLoading();
                    // 保存凭证到本地存储
                    localStorage.setItem('admin_credentials', credentials);
                    
                    // 关闭模态框
                    const loginModal = bootstrap.Modal.getInstance(document.getElementById('loginModal'));
                    loginModal.hide();
                    
                    // 初始化页面
                    init();
                },
                error: function(xhr) {
                    hideLoading();
                    console.error('Login failed:', xhr);
                    if (xhr.status === 401 || xhr.status === 403) {
                        showLoginError('用户名或密码错误');
                    } else {
                        showLoginError('服务器错误，请稍后再试');
                    }
                }
            });
        }
        
        // 显示登录错误
        function showLoginError(message) {
            const errorEl = $('#loginError');
            errorEl.text(message);
            errorEl.removeClass('d-none');
        }
        
        // 加载日志统计信息
        function loadLogStats() {
            $.ajax({
                url: '/api/admin/logs/stats',
                type: 'GET',
                headers: {
                    'Authorization': `Basic ${credentials}`
                },
                success: function(response) {
                    if (response.code === 0) {
                        updateStatsUI(response.data);
                    } else {
                        console.error('获取日志统计失败:', response.msg);
                    }
                },
                error: function(xhr) {
                    console.error('获取日志统计请求失败:', xhr);
                    if (xhr.status === 401 || xhr.status === 403) {
                        // 凭证无效，重新登录
                        localStorage.removeItem('admin_credentials');
                        showLoginModal();
                    }
                }
            });
        }
        
        // 更新统计UI
        function updateStatsUI(stats) {
            $('#totalFilesCount').text(stats.totalFiles);
            
            let totalErrorFiles = 0;
            Object.values(stats.categories).forEach(cat => {
                totalErrorFiles += cat.errorFiles;
            });
            $('#errorFilesCount').text(totalErrorFiles);
            
            // 格式化大小
            $('#totalSize').text(formatBytes(stats.totalSize));
            
            // 格式化错误率
            $('#errorRate').text((stats.errorRate * 100).toFixed(2) + '%');
        }
        
        // 加载日志文件列表
        function loadLogFiles(category) {
            $.ajax({
                url: `/api/admin/logs?category=${category}`,
                type: 'GET',
                headers: {
                    'Authorization': `Basic ${credentials}`
                },
                success: function(response) {
                    if (response.code === 0) {
                        logFiles = response.data;
                        renderLogFilesList(logFiles);
                    } else {
                        console.error('获取日志文件列表失败:', response.msg);
                    }
                },
                error: function(xhr) {
                    console.error('获取日志文件列表请求失败:', xhr);
                }
            });
        }
        
        // 渲染日志文件列表
        function renderLogFilesList(files) {
            const listEl = $('#logFilesList');
            
            if (files.length === 0) {
                listEl.html('<div class="text-center p-3 text-muted">没有找到日志文件</div>');
                return;
            }
            
            let html = '';
            files.forEach(file => {
                const isError = file.isError;
                const iconClass = isError ? 'fa-exclamation-circle text-danger' : 'fa-file-alt text-primary';
                const errorClass = isError ? 'file-error' : '';
                
                html += `
                    <a href="javascript:void(0)" class="list-group-item list-group-item-action ${errorClass}" 
                       data-file="${file.name}" data-path="${file.path}">
                        <div class="d-flex justify-content-between align-items-center">
                            <div>
                                <i class="fas ${iconClass} me-2"></i>
                                ${file.name}
                            </div>
                            <span class="badge bg-secondary">${formatBytes(file.size)}</span>
                        </div>
                        <small class="text-muted">${formatDate(file.modified)}</small>
                    </a>
                `;
            });
            
            listEl.html(html);
            
            // 绑定文件点击事件
            $('.list-group-item').click(function() {
                $('.list-group-item').removeClass('active');
                $(this).addClass('active');
                
                const fileName = $(this).data('file');
                const filePath = $(this).data('path');
                
                loadLogContent(filePath);
                currentFile = filePath;
                
                // 更新标题
                $('#currentLogTitle').html(`<i class="fas fa-file-alt me-2"></i> ${fileName}`);
                
                // 启用下载按钮
                $('#downloadBtn').prop('disabled', false);
            });
        }
        
        // 加载日志内容
        function loadLogContent(filePath) {
            showLoading();
            
            $.ajax({
                url: `/api/admin/logs/${filePath}?lines=2000`,
                type: 'GET',
                headers: {
                    'Authorization': `Basic ${credentials}`
                },
                success: function(response) {
                    hideLoading();
                    
                    if (response.code === 0) {
                        const contentEl = $('#logContent');
                        
                        // 解析和格式化日志内容
                        const formattedContent = formatLogContent(response.data.content);
                        contentEl.html(formattedContent);
                        
                        // 更新日志统计
                        $('#totalLines').text(response.data.totalLines);
                        $('#displayedLines').text(response.data.returnedLines);
                        
                        // 滚动到底部
                        contentEl.scrollTop(contentEl[0].scrollHeight);
                    } else {
                        console.error('获取日志内容失败:', response.msg);
                    }
                },
                error: function(xhr) {
                    hideLoading();
                    console.error('获取日志内容请求失败:', xhr);
                    
                    const contentEl = $('#logContent');
                    contentEl.html('<div class="text-center p-3 text-danger">获取日志内容失败</div>');
                }
            });
        }
        
        // 格式化日志内容
        function formatLogContent(content) {
            if (!content) return '<div class="text-center p-3 text-muted">日志内容为空</div>';
            
            const lines = content.split('\n');
            let html = '';
            
            lines.forEach(line => {
                if (line.trim() === '') return;
                
                // 尝试解析日志级别
                let levelClass = '';
                
                if (line.includes('[ERROR]')) {
                    levelClass = 'log-level-ERROR';
                } else if (line.includes('[WARN]')) {
                    levelClass = 'log-level-WARN';
                } else if (line.includes('[INFO]')) {
                    levelClass = 'log-level-INFO';
                } else if (line.includes('[DEBUG]')) {
                    levelClass = 'log-level-DEBUG';
                }
                
                // 格式化时间戳和类别
                line = line.replace(/\[([\d\-\s:]+)\]/g, '<span class="timestamp">[$1]</span>');
                line = line.replace(/\[(app|monitor|system)\]/g, '<span class="log-category">[$1]</span>');
                
                html += `<div class="log-line ${levelClass}">${line}</div>`;
            });
            
            return html;
        }
        
        // 处理类别切换
        function handleCategoryChange() {
            $('.category-btn').removeClass('active');
            $(this).addClass('active');
            
            currentCategory = $(this).data('category');
            loadLogFiles(currentCategory);
            
            // 重置当前文件
            currentFile = null;
            $('#currentLogTitle').html('<i class="fas fa-file-alt me-2"></i> 选择文件查看内容');
            $('#logContent').html('<div class="text-center p-3 text-muted">请选择左侧的日志文件查看内容</div>');
            $('#downloadBtn').prop('disabled', true);
        }
        
        // 过滤日志文件
        function filterLogFiles() {
            const searchTerm = $('#fileSearchInput').val().toLowerCase();
            
            if (searchTerm === '') {
                renderLogFilesList(logFiles);
                return;
            }
            
            const filteredFiles = logFiles.filter(file => 
                file.name.toLowerCase().includes(searchTerm)
            );
            
            renderLogFilesList(filteredFiles);
        }
        
        // 过滤日志内容
        function filterLogContent() {
            const searchTerm = $('#logSearchInput').val().toLowerCase();
            
            if (!currentFile) return;
            
            $('.log-line').each(function() {
                const lineText = $(this).text().toLowerCase();
                $(this).toggle(lineText.includes(searchTerm));
            });
            
            // 更新显示的行数
            updateDisplayedLines();
        }
        
        // 只显示错误日志
        function toggleErrorFilter() {
            const btn = $('#filterErrorBtn');
            const isActive = btn.hasClass('btn-danger');
            
            if (isActive) {
                // 取消筛选
                btn.removeClass('btn-danger').addClass('btn-outline-secondary');
                $('.log-line').show();
            } else {
                // 只显示错误
                btn.removeClass('btn-outline-secondary').addClass('btn-danger');
                $('.log-line').hide();
                $('.log-level-ERROR').show();
            }
            
            // 更新显示的行数
            updateDisplayedLines();
        }
        
        // 更新显示的行数
        function updateDisplayedLines() {
            const displayedLines = $('.log-line:visible').length;
            $('#displayedLines').text(displayedLines);
        }
        
        // 切换自动刷新
        function toggleAutoRefresh() {
            const isChecked = $('#autoRefreshSwitch').prop('checked');
            
            if (isChecked && currentFile) {
                // 启用自动刷新
                autoRefreshInterval = setInterval(() => {
                    loadLogContent(currentFile);
                }, 10000); // 每10秒刷新一次
            } else {
                // 禁用自动刷新
                if (autoRefreshInterval) {
                    clearInterval(autoRefreshInterval);
                    autoRefreshInterval = null;
                }
            }
        }
        
        // 清空日志内容
        function clearLogContent() {
            $('#logContent').html('<div class="text-center p-3 text-muted">日志内容已清空</div>');
            $('#totalLines').text('0');
            $('#displayedLines').text('0');
        }
        
        // 下载当前日志
        function downloadCurrentLog() {
            if (!currentFile) return;
            
            const anchor = document.createElement('a');
            anchor.href = `/api/admin/logs/${currentFile}?token=${encodeURIComponent(credentials)}`;
            anchor.target = '_blank';
            anchor.download = currentFile.split('/').pop();
            anchor.click();
        }
        
        // 刷新数据
        function refreshData() {
            loadLogStats();
            loadLogFiles(currentCategory);
            
            if (currentFile) {
                loadLogContent(currentFile);
            }
        }
        
        // 格式化字节大小
        function formatBytes(bytes, decimals = 2) {
            if (bytes === 0) return '0 B';
            
            const k = 1024;
            const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
            
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            
            return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
        }
        
        // 格式化日期
        function formatDate(dateString) {
            const date = new Date(dateString);
            return date.toLocaleString('zh-CN');
        }
        
        // 显示加载遮罩
        function showLoading() {
            $('#loadingOverlay').show();
        }
        
        // 隐藏加载遮罩
        function hideLoading() {
            $('#loadingOverlay').hide();
        }
    </script>
</body>
</html> 